

from langgraph.graph import Graph,START, END
from typing import Dict, Any

from pydantic.config import JsonDict

from config.common_config import DATABASE_CONFIG
from database.embedding_model import EmbeddingModel
from database.milvus_client import MilvusClient
from models.chat_record import ChatRecord, Role, ContentType

import requests

from models.workflow.inputModel import InputModel
from models.workflow.stateModel import StateModel
import logging
import threading

from server.chat_record_server import ChatRecordServer

logger = logging.getLogger(__name__)

class ChatFlow:
    _instance = None
    _lock = threading.Lock()
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            with cls._lock:
                if not cls._instance:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self, ollama_api_url: str = "http://192.168.3.111:11434/api/chat", model_name: str = "qwen2.5:32b"):
        # Ollama 配置
        self.OLLAMA_API_URL = ollama_api_url
        self.MODEL_NAME = model_name
        self.milvus_client = ChatRecordServer(
            host=DATABASE_CONFIG["HOST"],
    port=DATABASE_CONFIG["PORT"],
    user=DATABASE_CONFIG["USER"],
    pwd=DATABASE_CONFIG["PASSWORD"])
        self.embedding_model = EmbeddingModel()
        self.app=self.createWorkFolow()

    ##定义节点函数

    ## 1.输入
    def inputParser(self,input:InputModel) -> StateModel:
        state=StateModel(userId= input.userId)
        state.currentReq=input
        state.currentReqTex=input.content
        print(f"节点1: 组装上下文 ")
        return state


    ## 2.提取关键词
    def getKeywords(self,state:StateModel) -> StateModel:

        prompt = f"""
            ##任务
            请你将用户给定的问题进行提取关键内容，用于进行检索知识库内容。
            ## 输出
            输出多个关键字或者关键句，关键字或者关键句之间使用空格隔开，无需其他多余的文且禁止直接回答用户的问题。
            ## 用户输入
            {state.currentReqTex}
            """
        messages = [
            {"role": "system", "content": "你是一个关键词总结工具，请按下列要求提取关键词"},
            {"role": "user", "content": prompt}
        ]

        ##调用大模型
        response = requests.post(
            self.OLLAMA_API_URL,
            json={
                "model": self.MODEL_NAME,
                "messages": messages,
                "stream": False,
                "options": {"temperature": 0.3}
            },
            timeout=60
        )
        conten = response.json()["message"]["content"]

        state.keyword=conten
        print(f"提取关键")
        return state

    ## 3.获取外存中的历史记忆
    def getLongTimeHistoryMem(self,state:StateModel) -> StateModel:
        kw= state.keyword
        query_embedding = self.embedding_model.get_embedding(kw)

        records = self.milvus_client.search_records(
            user_id=state.userId,
            query_embedding=query_embedding
        )

        chat_history = []
        for r in records:
            content = f"{r['content']}"
            # content = f"{r['role']}: {r['content']}"
            if r['content_des']:
                content += f" (描述: {r['content_des']})"
            chat_history.append(content)

        chatHistory = "\n\n".join(chat_history)
        state.longTimeMem=chatHistory
        return state


    def generate_family_chat_response(self,
            chat_history,  # 当前聊天记录
            model="gpt-3.5-turbo"  # 可替换为其他模型
    ):
        # 2. 构建提示词（Prompt）
        prompt = f"""
        你正在与亲人聊天，请根据以下信息生成一段温暖、自然的回复：
    
        ---
        [过往聊天记录]
        {chat_history}
        ---
    
        要求：
        1. 语气亲切，像家人之间的日常对话。
        2. 适当引用回忆或经历增强情感共鸣。
        3. 如果当前聊天涉及问题（如健康、节日计划），优先回答实际问题。
        """


    ## 6.generate_reponse 生成回答

    def generateReponse(self,state:StateModel) -> StateModel:

        prompt= self.generate_family_chat_response(state.longTimeMem)

        messages = [
            {"role": "system", "content": "你是一个善于与亲人沟通的助手，语气温暖且充满关怀。"},
            {"role": "user", "content": prompt}
        ]

        ##调用大模型
        response = requests.post(
            self.OLLAMA_API_URL,
            json={
                "model": self.MODEL_NAME,
                "messages": messages,
                "stream": False,
                "options": {"temperature": 0.3}
            },
            timeout=60
        )
        conten= response.json()["message"]["content"]

        print(f"llm生成回答：{conten}")
        state.res=conten
        return state

    def saveChatHistory(self,state:StateModel) -> str:

        a=state.to_dict()
        print("2222222222")
        print( a)
        print("3333333333333")
        rt= a["currentReqTex"]
        sr= a["res"]
        content=f"""
        user：{rt}
        assistant :{sr}
        """

        record = ChatRecord(
            user_id=state.userId,
            content_type=ContentType(state.contentType),
            content=content,
            role=Role(state.role),
            content_des=state.contentDes
        )

        embedding = self.embedding_model.get_embedding(record.chat_content)
        record_id = self.milvus_client.insert_record(record, embedding)
        return state.res

    def createWorkFolow(self):
        # 构建工作流
        workflow = Graph()

        # 添加节点
        workflow.add_node("start", self.inputParser)

        workflow.add_node("getKeywords", self.getKeywords)
        workflow.add_node("getLongTimeHistoryMem", self.getLongTimeHistoryMem)
        workflow.add_node("generateReponse", self.generateReponse)
        workflow.add_node("saveChatHistory", self.saveChatHistory)

        workflow.add_node("end", self.saveChatHistory)

        # 添加边
        workflow.add_edge(START, "start")
        workflow.add_edge("start", "getKeywords")

        workflow.add_edge("getKeywords", "getLongTimeHistoryMem")

        workflow.add_edge("getLongTimeHistoryMem", "generateReponse")

        workflow.add_edge("generateReponse", "saveChatHistory")

        workflow.add_edge("saveChatHistory", "end")

        workflow.add_edge("end", END)

        app = workflow.compile()

        return app

    def chat(self,userId:str,req:str):

        input = InputModel(userId= userId, contentType= "text", content= req)
        ress=self.app.invoke(input)
        return ress

































